#include "AKCommon.h"
#include "CDSQBoard.h"
#include <math.h>
#include <memory.h>

void CDSQBoard::backToInitialState()
{
	memcpy(m_CurPosition, InitChessBoard, 63*sizeof(PieceIndex));
	InitChessEvaluations();
}

void CDSQBoard::InitChessEvaluations()
{
	m_BaseValue[LMice]		= BASEVALUE_Mice;
	m_BaseValue[LCat]		= BASEVALUE_Cat;
	m_BaseValue[LDog]		= BASEVALUE_Dog;
	m_BaseValue[LWolf]		= BASEVALUE_Wolf;
	m_BaseValue[LPanther]   = BASEVALUE_Panther;
	m_BaseValue[LTiger]		= BASEVALUE_Tiger;
	m_BaseValue[LLion]		= BASEVALUE_Lion;
	m_BaseValue[LElephant]  = BASEVALUE_Elephant;
	m_BaseValue[RMice]		= BASEVALUE_Mice;
	m_BaseValue[RCat]		= BASEVALUE_Cat;
	m_BaseValue[RDog]		= BASEVALUE_Dog;
	m_BaseValue[RWolf]		= BASEVALUE_Wolf;
	m_BaseValue[RPanther]	= BASEVALUE_Panther;
	m_BaseValue[RTiger]		= BASEVALUE_Tiger;
	m_BaseValue[RLion]		= BASEVALUE_Lion;
	m_BaseValue[RElephant]  = BASEVALUE_Elephant;
}

void CDSQBoard::CreatePossibleMove(/*PieceIndex position[][Col], */int depth, int nSide)
{
	PieceIndex nChessID;
	int i,j;
	
	m_PossibleMovementCounter = 0;
	for (i = 0; i < 7; i++)
		for (j = 0; j < 9; j++)
		{
			if (m_CurPosition[i][j] != NOCHESS && !IsOther(m_CurPosition[i][j]))
			{
				nChessID = m_CurPosition[i][j];
				// check the valid turns
				if (!nSide && IsLeft(nChessID))
					continue;
				if (nSide && IsRight(nChessID))
					continue;
				
				switch(nChessID)
				{
					case LLion:
					case RLion:
						Gen_LionMove(i, j, depth);
						break;
						
					case LTiger:
					case RTiger:
						Gen_TigerMove(i, j, depth);
						break;
						
					case Trap:
					case Water:
					case LHome:
					case RHome:
					case NOCHESS:
						break;
						
					default:
						Gen_Move(i, j, depth);
				}
			}
		}
}

void CDSQBoard::AddMove(int nFromX, int nFromY, int nToX, int nToY, int depth)
{
	//add move to the list
	m_MoveList[depth][m_PossibleMovementCounter].From.x = nFromX;
	m_MoveList[depth][m_PossibleMovementCounter].From.y = nFromY;
	m_MoveList[depth][m_PossibleMovementCounter].To.x = nToX;
	m_MoveList[depth][m_PossibleMovementCounter].To.y = nToY;
	
	m_PossibleMovementCounter++;
}

void CDSQBoard::Gen_LionMove(/*PieceIndex position[][Col], */int i, int j, int depth)
{
	int x,y;
	
	Gen_Move(i, j, depth);
	
	if((j-1)>=0 && m_CurPosition[i][j-1] == Water)
	{
		x=j-4;
		y=i;
		if((x >= 0) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
	
	if((i+1)<7 && m_CurPosition[i+1][j] == Water)
	{
		x=j;
		y=i+3;
		if((y < 7) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
	
	if((i-1)>=0 && m_CurPosition[i-1][j] == Water)
	{
		x=j;
		y=i-3;
		if((y >= 0) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
	
	if((j+1)<9 && m_CurPosition[i][j+1] == Water)
	{
		x=j+4;
		y=i;
		if((x < 9) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
}

void CDSQBoard::Gen_TigerMove(/*PieceIndex position[][Col], */int i, int j, int depth)
{
	int x,y;
	
	Gen_Move(i, j, depth);
	
	if((j-1)>=0 && m_CurPosition[i][j-1] == Water)
	{
		x=j-4;
		y=i;
		if((x >= 0) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
	
	if((i-1)>=0 && m_CurPosition[i-1][j] == Water)
	{
		x=j;
		y=i-3;
		if((y >= 0) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
	
	if((i+1)<7 && m_CurPosition[i+1][j] == Water)
	{
		x=j;
		y=i+3;
		if((y < 7) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
	
	if((j+1)<9 && m_CurPosition[i][j+1] == Water)
	{
		x=j+4;
		y=i;
		if((x < 9) && IsValidMove(j, i, x, y))
			AddMove(j, i, x, y, depth);
	}
}

void CDSQBoard::Gen_Move(/*PieceIndex position[][Col], */int i, int j, int depth)
{
	int x,y;
	
	//to left
	x=j-1;
	y=i;
	if((x >= 0) && IsValidMove(j, i, x, y))
		AddMove(j, i, x, y, depth);
	
	//down
	x=j;
	y=i+1;
	if((y < 7) && IsValidMove(j, i, x, y))
		AddMove(j, i, x, y, depth);
	
	//up
	x=j;
	y=i-1;
	if((y >= 0) && IsValidMove(j, i, x, y))
		AddMove(j, i, x, y, depth);
	
	//to right
	x=j+1;
	y=i;
	if((x < 9) && IsValidMove(j, i, x, y))
		AddMove(j, i, x, y, depth);
}

int CDSQBoard::IsValidMove(/*PieceIndex position[][Col], */int nFromX, int nFromY, int nToX, int nToY)
{
	PieceIndex nMoveChessID, nTargetID;
	
	if( m_CurPosition[nFromY][nFromX] == NOCHESS || IsOther(m_CurPosition[nFromY][nFromX]) )
		return false; //check the source
	
	if( !(nFromX == nToX || nFromY == nToY) )
		return false; //can not run across
	
	if (nFromY ==  nToY && nFromX == nToX)
		return false;   //the destination as same as the source
	
	nMoveChessID = m_CurPosition[nFromY][nFromX];
	nTargetID = m_CurPosition[nToY][nToX];
	
	if( nTargetID==LHome && IsLeft(nMoveChessID) )
		return false;
	if( nTargetID==RHome && IsRight(nMoveChessID) )
		return false;
	if (IsSameSide(nMoveChessID, nTargetID))
		return false;   //can not defeat the own-side chess.
    if( nTargetID == Water && (nMoveChessID!=LMice && nMoveChessID!=RMice) )
        return false;   //only mouse can dive into water
	
	//check the type of the source-chess
	
	//only the tiger and the lion can jump
	if( !(nMoveChessID == LTiger || nMoveChessID == LLion || nMoveChessID == RTiger || nMoveChessID == RLion) )
	{
		if( !(abs(nFromX-nToX)==1 || abs(nFromY-nToY)==1) )
			return false;
	}
	//must be tiger or lion
	else
	{
		//move vertically
		if(nFromX==nToX)
		{
			//is jump?
			if( abs(nFromY-nToY)>1 )
			{
				//move up
				if( nFromY>nToY )
				{
					//in case that the mouse in the water...
					if( m_CurPosition[nFromY-1][nFromX]!=Water || m_CurPosition[nFromY-2][nFromX]!=Water )
						return false;
				}
				//move down
				else// assert( nFromY<nToY )
				{
					if( m_CurPosition[nFromY+1][nFromX]!=Water || m_CurPosition[nFromY+2][nFromX]!=Water )
						return false;
				}
			}
		}
		//move horizontally
		else if(nFromY==nToY)
		{
			//is jump?
			if( abs(nFromX-nToX)>1 )
			{
				//move left
				if( nFromX>nToX )
				{
					if( m_CurPosition[nFromY][nFromX-1]!=Water || m_CurPosition[nFromY][nFromX-2]!=Water || m_CurPosition[nFromY][nFromX-3]!=Water )
						return false;
				}
				//move right
				else// assert( nFromX<nToX )
				{
					if( m_CurPosition[nFromY][nFromX+1]!=Water || m_CurPosition[nFromY][nFromX+2]!=Water || m_CurPosition[nFromY][nFromX+3]!=Water )
						return false;
				}
			}
		}
		else
			return false;
	}
	
	//check the desternation-chess
	if( nTargetID && !IsOther(nTargetID) )
	{
		//source-chess is right-side
		if ( IsRight(nMoveChessID) )
		{
			//the elephants only can eat the mouse when the latter in trap
			if( (nMoveChessID==16 && nTargetID==1) && (InitChessBoard[nToY][nToX] != Trap) )
				return false;
			
			//mouse eat elephants
			if( nMoveChessID==9 && nTargetID==8 )
			{
				if(InitChessBoard[nFromY][nFromX] == Water) //mouse can not be in the water
					return false;
				else
					return true;
			}
			if( InitChessBoard[nToY][nToX] != Trap && nMoveChessID-8 < nTargetID )
				return false;//source-chess can not eat the desternation-chess
			
			if(InitChessBoard[nToY][nToX] == Water) //can not eat the mouse which are in the water
				return false;
		}
		else //assert( IsLeft(nMoveChessID) )
		{
			if( (nMoveChessID==8 && nTargetID==9) && (InitChessBoard[nToY][nToX] != Trap) )
				return false;
			if( nMoveChessID==1 && nTargetID==16 )
			{
				if(InitChessBoard[nFromY][nFromX] == Water)
					return false;
				else
					return true;
			}
			if( InitChessBoard[nToY][nToX] != Trap && nMoveChessID < nTargetID-8 )
				return false;
			
			if(InitChessBoard[nToY][nToX] == Water)
				return false;
		}
	}
	
	//include the case which the TargetID is HOME
	return true;
}

unsigned int CDSQBoard::MakeMove(PieceMove* move)
{
	PieceIndex nChessID;
	//save the TargetID for redo
	nChessID = m_CurPosition[move->To.y][move->To.x];
	//execute the move
	m_CurPosition[move->To.y][move->To.x] = m_CurPosition[move->From.y][move->From.x];
	//recover the source-grid
	if( !IsOther(InitChessBoard[move->From.y][move->From.x]) )
		m_CurPosition[move->From.y][move->From.x] = NOCHESS;
	else
		m_CurPosition[move->From.y][move->From.x] = InitChessBoard[move->From.y][move->From.x];
	
	return nChessID;
}

void CDSQBoard::UnMakeMove(PieceMove* move,PieceIndex nChessID)
{
	//redo
	m_CurPosition[move->From.y][move->From.x] = m_CurPosition[move->To.y][move->To.x];
	m_CurPosition[move->To.y][move->To.x] = nChessID;
}

int CDSQBoard::IsGameOver(/*PieceIndex position[][9], */int nDepth, AKSideIndex side)
{
	int dep;
	
	if( side == Left )
		dep = !(nDepth%2);
	if( side == Right )
		dep = nDepth%2;
	
	if( dep==1 )
	{
		if( m_CurPosition[3][0]!=LHome )
		{
			return 18880+nDepth;
		}
		else if( m_CurPosition[3][8]!=RHome )
			return -18880-nDepth;
	}
	else
	{
		if( m_CurPosition[3][0]!=LHome )
		{
			return -18880-nDepth;
		}
		else if( m_CurPosition[3][8]!=RHome )
			return 18880+nDepth;
	}
	
	return 0;
}

int CDSQBoard::Evaluate(/*PieceIndex position[][9], */int bIsLTurn)
{
	PieceIndex i,j,k;
	PieceIndex nChessType,nTargetType;
	
	//inital the value-buffers
	memset(m_chessValue, 0, 63*sizeof(int));
	memset(m_AttackPos, 0, 63*sizeof(int));
	memset(m_GuardPos, 0, 63*sizeof(int));
	
	//the first search of the board
	for(i = 0; i < 7; i++)
		for(j = 0; j < 9; j++)
		{
			//make sure there is a real chess
			if( m_CurPosition[i][j] != NOCHESS && !IsOther(m_CurPosition[i][j]) )
			{
				nChessType = m_CurPosition[i][j];
				//get the reachable pieces( include the chess that will be eaten.)
				GetRelatePiece(j, i);
				
				//for each reachable pieces
				for (k = 0; k < m_RelatePosCounter; k++)
				{
					nTargetType = m_CurPosition[RelatePos[k].y][RelatePos[k].x];
					
					//count the guarded-places
					if (IsSameSide(nChessType, nTargetType))
					{
						if( nChessType>nTargetType )
							m_GuardPos[RelatePos[k].y][RelatePos[k].x]++;
					}
					else
					{
						if( !IsOther(nTargetType) && nTargetType )
						{
							m_AttackPos[RelatePos[k].y][RelatePos[k].x]++;
						}
						else if( nTargetType == LHome )
						{
							if(!bIsLTurn)
								return 18888;
						}
						else if( nTargetType == RHome )
						{
							if(bIsLTurn)
								return 18888;
						}
					}
				}
			}
		}
	
	//the discount-value
	int nHalfvalue;
	
	//the second search of the board
	for(i = 0; i < 7; i++)
		for(j = 0; j < 9; j++)
		{
			if(m_CurPosition[i][j] != NOCHESS && !IsOther(m_CurPosition[i][j]))
			{
				nChessType = m_CurPosition[i][j];
				nHalfvalue = m_BaseValue[nChessType]/5;
				
				//whether is a trap
				if(InitChessBoard[i][j] == Trap)
					m_chessValue[i][j] -= BASEVALUE_Elephant * 1.5;
				else
					m_chessValue[i][j] += m_BaseValue[nChessType];
				
				//current position has a left-hand chess
				if (IsLeft(nChessType))
				{
					//the chess already in the RHome
					if(InitChessBoard[i][j] == RHome)
						return 18888;
					
					//the position has the attacked-pos
					if (m_AttackPos[i][j])
					{
						if (bIsLTurn)
						{
							//minus a low value
							m_chessValue[i][j] -= (nHalfvalue<<1);
							//if has a guarded-pos
							if (m_GuardPos[i][j])
								m_chessValue[i][j] += nHalfvalue * 1.5;
						}
						else
						{
							//lose a high value
							m_chessValue[i][j] -= nHalfvalue*5;
							if (m_GuardPos[i][j])
								m_chessValue[i][j] += (nHalfvalue<<1);
						}
					}
					else
					{
						if (m_GuardPos[i][j])
							m_chessValue[i][j] += 5;
					}
					//the big-chess is really near to the Target-home, add some values
					if( (nChessType==LLion || nChessType==LTiger) && 3==i )
						m_chessValue[i][j] += 50;
					if( (2==i && 1==j) || (4==i && 1==j) )
						m_chessValue[i][j] += 5;
				}
				else //assert(IsRight(nChessType))
				{
					if(InitChessBoard[i][j] == LHome)
						return 18888;
					
					if (m_AttackPos[i][j])
					{
						if (!bIsLTurn)
						{
							m_chessValue[i][j] -= (nHalfvalue<<1);
							if (m_GuardPos[i][j])
								m_chessValue[i][j] += nHalfvalue * 1.5;
						}
						else
						{
							m_chessValue[i][j] -= nHalfvalue*5;
							if (m_GuardPos[i][j])
								m_chessValue[i][j] += (nHalfvalue<<1);
						}
					}
					else
					{
						if (m_GuardPos[i][j])
							m_chessValue[i][j] += 5;
					}
					if( (nChessType==RLion || nChessType==RTiger) && 3==i )
						m_chessValue[i][j] += 50;
					if( (2==i && 7==j) || (4==i && 7==j) )
						m_chessValue[i][j] += 5;
				}
			}
		}
	
	// get the total value of each side
	int nRValue = 0;
	int nLValue = 0;
	
	for(i = 0; i < 7; i++)
		for(j = 0; j < 9; j++)
		{
			nChessType = m_CurPosition[i][j];
			if (nChessType != NOCHESS && !IsOther(m_CurPosition[i][j]))
			{
				if (IsLeft(nChessType))
				{
					if( nChessType==LLion || nChessType==LTiger)
						nLValue += (m_chessValue[i][j]+j*m_BaseValue[nChessType]/10);
					else
						nLValue += (m_chessValue[i][j]+j*20);
				}
				else
				{
					if( nChessType==RLion || nChessType==RTiger)
						nRValue += (m_chessValue[i][j]+(9-j)*m_BaseValue[nChessType]/10);
					else
						nRValue += (m_chessValue[i][j]+(9-j)*20);
				}
			}
		}
	
	if( bIsLTurn )
		return nLValue-nRValue;
	else
		return nRValue-nLValue;
}

void CDSQBoard::GetRelatePiece(int j, int i)
{
    m_RelatePosCounter = 0;
	PieceIndex nChessID;
	int x,y;
	
	nChessID = m_CurPosition[i][j];
	
	x = j-1;
	y = i;
	if( x>=0 && IsRelativePiece(j, i, x, y) )
		AddPoint(x, y);
	
	x = j+1;
	y = i;
	if( x<9 && IsRelativePiece(j, i, x, y) )
		AddPoint(x, y);
	
	x = j;
	y = i-1;
	if( y>=0 && IsRelativePiece(j, i, x, y) )
		AddPoint(x, y);
	
	x = j;
	y = i+1;
	if( y<7 && IsRelativePiece(j, i, x, y) )
		AddPoint(x, y);
	
	if(nChessID == LTiger || nChessID == LLion || nChessID == RTiger || nChessID == RLion )
	{
		x = j-4;
		y = i;
		if( x>=0 && m_CurPosition[i][j-1]==Water && IsRelativePiece(j, i, x, y) )
			AddPoint(x, y);
		
		x = j+4;
		y = i;
		if( x<9 && m_CurPosition[i][j+1]==Water && IsRelativePiece(j, i, x, y) )
			AddPoint(x, y);
		
		x = j;
		y = i-3;
		if( y>=0 && m_CurPosition[i-1][j]==Water && IsRelativePiece(j, i, x, y) )
			AddPoint(x, y);
		
		x = j;
		y = i+3;
		if( y<7 && m_CurPosition[i+1][j]==Water && IsRelativePiece(j, i, x, y) )
			AddPoint(x, y);
	}
}


//notic: the function just a little like the function IsValidMove(), but not the same
int CDSQBoard::IsRelativePiece(/*PieceIndex position[][9], */int nFromX, int nFromY, int nToX, int nToY)
{
	PieceIndex nMoveChessID, nTargetID;
	
	if( m_CurPosition[nFromY][nFromX] == NOCHESS || IsOther(m_CurPosition[nFromY][nFromX]) )
		return false;
	
	if( !(nFromX == nToX || nFromY == nToY) )
		return false;
	
	if (nFromY ==  nToY && nFromX == nToX)
		return false;
	
	nMoveChessID = m_CurPosition[nFromY][nFromX];
	nTargetID = m_CurPosition[nToY][nToX];
	
	if( nTargetID==LHome && IsLeft(nMoveChessID) )
		return false;
	if( nTargetID==RHome && IsRight(nMoveChessID) )
		return false;
	if (IsSameSide(nMoveChessID, nTargetID))
	{
		if( InitChessBoard[nToY][nToX] == Water )
			return false;
		return true;	// 
	}
	
	if( nTargetID == Water && (nMoveChessID!=LMice && nMoveChessID!=RMice) )
		return false;	// rat goes into water
	else
	{
		if( !(nMoveChessID == LTiger || nMoveChessID == LLion || nMoveChessID == RTiger || nMoveChessID == RLion) )
		{
			if( !(abs(nFromX-nToX)==1 || abs(nFromY-nToY)==1) )
				return false;
		}
		else
		{
			if(nFromX==nToX)
			{
				if( abs(nFromY-nToY)>1 )
				{
					if( nFromY>nToY )
					{
						if( m_CurPosition[nFromY-1][nFromX]!=Water || m_CurPosition[nFromY-2][nFromX]!=Water)
							return false;
					}
					else if( nFromY<nToY )
					{
						if( m_CurPosition[nFromY+1][nFromX]!=Water || m_CurPosition[nFromY+2][nFromX]!=Water)
							return false;
					}
				}
			}
			else if(nFromY==nToY)
			{
				if( abs(nFromX-nToX)>1 )
				{
					if( nFromX>nToX )
					{
						if( m_CurPosition[nFromY][nFromX-1]!=Water || m_CurPosition[nFromY][nFromX-2]!=Water || m_CurPosition[nFromY][nFromX-3]!=Water )
							return false;
					}
					else if( nFromX<nToX )
					{
						if( m_CurPosition[nFromY][nFromX+1]!=Water || m_CurPosition[nFromY][nFromX+2]!=Water || m_CurPosition[nFromY][nFromX+3]!=Water )
							return false;
					}
				}
			}
			else
				return false;
		}
	}
	
	if( !IsOther(nTargetID) && nTargetID )
	{
		if ( IsRight(nMoveChessID) )
		{
			if( (nMoveChessID==16 && nTargetID==1) && (InitChessBoard[nToY][nToX] != Trap) )
				return false;
			if( nMoveChessID==9 && nTargetID==8 )
			{
				if(InitChessBoard[nFromY][nFromX] == Water) // rat cannot capture elephant when it's in water
					return false;
				else
					return true;
			}
			if( InitChessBoard[nToY][nToX] != Trap && nMoveChessID-8 < nTargetID )
				return false;	// piece ranking not sufficient
			
			if(InitChessBoard[nToY][nToX] == Water) // no piece can capture rat in water
				return false;
		}
		else
		{
			if( (nMoveChessID==8 && nTargetID==9) && (InitChessBoard[nToY][nToX] != Trap) )
				return false;
			if( nMoveChessID==1 && nTargetID==16 )
			{
				if(InitChessBoard[nFromY][nFromX] == Water) // rat cannot capture elephant when it's in water
					return false;
				else
					return true;
			}
			if( InitChessBoard[nToY][nToX] != Trap && nMoveChessID < nTargetID-8 )
				return false;	// piece ranking not sufficient
			
			if(InitChessBoard[nToY][nToX] == Water)
				return false;
		}
	}
	return true;
}

void CDSQBoard::AddPoint(int x, int y)
{
	RelatePos[m_RelatePosCounter].x = x;
	RelatePos[m_RelatePosCounter].y = y;
	m_RelatePosCounter++;
}